//! match: Rust 中没有类似于 C 的 switch 关键字，但它有用于模式匹配的 match，能实现同样的功能，并且强大太多。
//!

#[test]
pub fn match_demo_(){

    let x = 5;

    match x {
        1 => {
            println!("one")
        },
        2 => println!("two"),
        3 => println!("three"),
        4 => println!("four"),
        5 => println!("five"),
        _ => println!("something else"),
    }
}
/*模式匹配*/


enum Direction {
    East,
    West,
    North,
    South,
}
#[test]
pub fn match_demo(){
    let dir = Direction::South;
    match dir {
        Direction::East => println!("East"),
        Direction::North | Direction::South => {
            println!("South or North");
        },
        _ => println!("West"),
    }
}

enum Action {
    Say(String),
    MoveTo(i32, i32),
    ChangeColorRGB(u16, u16, u16),
}

#[test]
pub fn match_demo2(){
    let action = Action::Say("Hello Rust".to_string());
    match action {
        Action::Say(s) => {
            println!("{}", s);
        },
        Action::MoveTo(x, y) => {
            println!("point from (0, 0) move to ({}, {})", x, y);
        },
        Action::ChangeColorRGB(r, g, _) => {
            println!("change color into '(r:{}, g:{}, b:0)', 'b' has been ignored",
                     r, g,
            );
        }
    }
}
#[test]
pub fn match_demo3(){
    let x = 1;
    let c = 'c';

    match c {
        x => println!("x: {} c: {}", x, c), // c, c
    }

    println!("x: {}", x);
}

//解构
pub fn match_demo4(){
    struct Point {
        x: i64,
        y: i64,
    }
    let point = Point { x: 0, y: 3 };
    match point {
        //Point { x, y } => println!("({},{})", x, y),
        //Point { x: x1, y: y1} => println!("({},{})", x1, y1), //改变
        Point { y, .. } => println!("y is {}", y), //3 忽略字段
    }
}

//忽略和内存管理
pub fn match_demo5(){
    let tuple: (u32, String) = (5, String::from("five"));

    let (x, s) = tuple;

// 以下行将导致编译错误，因为String类型并未实现Copy, 所以tuple被整体move掉了。
// println!("Tuple is: {:?}", tuple);

    let tuple = (5, String::from("five"));

// 忽略String类型，而u32实现了Copy，则tuple不会被move
    let (x, _) = tuple;

    println!("Tuple is: {:?}", tuple);
}
//范围
pub fn match_demo6(){
    let x = 1;
    match x {
        1 ..= 10 => println!("一到十"),
        _ => println!("其它"),
    }
}
//多重匹配
pub fn match_demo7(){
    let x = 1;

    match x {
        1 | 2 => println!("一或二"),
        _ => println!("其他"),
    }
}

//ref 和 ref mut
// 前面我们了解到，当被模式匹配命中的时候，未实现Copy的类型会被默认的move掉，因此，原owner就不再持有其所有权。
// 但是有些时候，我们只想要从中拿到一个变量的（可变）引用，而不想将其move出作用域，怎么做呢？答：用ref或者ref mut。
#[test]
pub fn match_demo8(){
    let mut x = 5;
   
    match x {
        ref mut mr =>{

            println!("mut ref :{}", mr); //5
            *mr = 34;

        },//5
    }
// 当然了……在let表达式里也能用
    let ref mut mrx = x; //34
    println!("{}", x);
}

//变量绑定
//在模式匹配的过程内部，我们可以用@来绑定一个变量名，这在复杂的模式匹配中是再方便不过的，比如一个具名的范围匹配如下：
#[test]
pub fn match_demo9(){
    let x: u32 = 11_u32;
    match x {
        // 区间匹配 rust2021写法 ..=
        e @ 1..=11  => println!("get:{}", e),
        _ => (),
    }

    #[derive(Debug)]
    struct Person {
        name: Option<String>,
    }

    let name = "Steve".to_string();
    let x: Option<Person> = Some(Person { name: Some(name) });
    match x {
        Some(Person { name: ref a @ Some(_), .. }) => println!("{:?}", a), //Some("Steve")
        _ => {}
    }
}

//后置条件
//一个后置的if表达式可以被放在match的模式之后
pub fn match_demo10(){
    let x = 4;
    let y = false;

    match x {
        4 | 5 if y => println!("yes"), // 相当于:IF y AND (x IN List[4, 5])
        _ => println!("no"), //输出no
    }
}

